package executors

import db.Client
import db.{ File, Folder, FileManager }
import org.hibernate.{Session, SessionFactory}
import org.hibernate.cfg.Configuration
import client_updater.ClientsUpdater
import client_updater.FileUpdate
import scala.collection.mutable.LinkedList
import objects.File2
import scala.actors.Actor


/**
 * Processes an update about a file that was changed in a client's dropbox.<br>
 * communicates with the database and sends updates for other clients.
 */
class ChangedFileExecutor extends Actor {
  
  /**
   * the acting method of the actor
   */
  def act(){
    loop{
      react{
        case (changedFile : File2)=> 
          sender ! execute(changedFile)
        case "Quit" => exit()
        case _ => println("ChangedFileExecutor received unknown message")
      }
    }
  }

  /**
   * receives a File2 that contains details about a file that was changed in a client's dropbox.<br>
   * communicates with the database and the disk, and sends updates for other clients.<br>
   * returns true if the new file already exists in the database and false if it's need to be uploaded.<br>
   * @param - changedFile : File2, details about the changed file<br>
   * @returns - true if the new file already exists in the database and false if it's need to be uploaded.
   */
  private def execute(changedFile : File2) : Boolean = {
    val cfg = new Configuration()
    var sessionFactory = null.asInstanceOf[SessionFactory]
    var session = null.asInstanceOf[Session]
    try{
	    sessionFactory = cfg.configure().buildSessionFactory()
	    session = sessionFactory.openSession()
	    //check if the new file exists on the DB
	    var query = session.createQuery("from File f where f.fileID = " + changedFile.code +
	    							" and f.size = " + changedFile.size)
	    var newFileInstances = query.list.toArray
	    if(newFileInstances.isEmpty){
	      //getting all instances of the old file
	      query = session.createQuery("from File f where f.fileName = " + changedFile.name +
	    							" and f.parentFolder = " + changedFile.parent)
	      var fileToDelete = query.list.toArray
	      var fileManager = new FileManager(session)
	      fileManager.deleteFile(fileToDelete.asInstanceOf[File])
	      //updating the clients
	      query = session.createQuery("from Folder f where f.folderID = "+fileToDelete.asInstanceOf[File].getParentFolder)
	      val folderUsers = query.list.toArray
	      var clients = new LinkedList[Client]
		  //collects all relevant clients
		  for( f <- folderUsers ){
		    query = session.createQuery("from Clients where user_ID = " + f.asInstanceOf[Folder].getUserID )
		    var newClients = query.list().toArray
		    for( c <- newClients ){
		      clients = clients :+ c.asInstanceOf[Client]
		    }
		  }
	      for( c <- clients ){
	    	if( c.getClientID != changedFile.cid ){
	    	  ClientsUpdater.addUpdate(c.getClientID, 
	    	      new FileUpdate("changededFile", changedFile.name, changedFile.parent, changedFile.code))
	    	}
	      }
	      session.flush
	      //checking if the old file still exists
	      query = session.createQuery("from File f where f.fileID = "+fileToDelete.asInstanceOf[File].getFileID
	          							+" and f.size = "+fileToDelete.asInstanceOf[File].getSize)
	      if(query.list.toArray.isEmpty){
	        //deleting actual file from disk
	        val file = new java.io.File("storage\\" + fileToDelete.asInstanceOf[File].getFileID)
	        file.delete
	      }
	      session.flush
	      return false
	    }
	    else{
	      //getting all instances of the old file
	      query = session.createQuery("from File f where f.fileName = " + changedFile.name +
	    							" and f.parentFolder = " + changedFile.parent)
	      var fileToChange = query.list.toArray
	      var fileManager = new FileManager(session)
	      //updating the file
	      var file = fileToChange.first.asInstanceOf[File]
	      file.setFileID(changedFile.code)
	      file.setSize(changedFile.size)
	      fileManager.updateFile(file)
	      //updating the clients
	      query = session.createQuery("from Folder f where f.folderID = "+file.getParentFolder)
	      val folderUsers = query.list.toArray
	      var clients = new LinkedList[Client]
		  //collects all relevant clients
		  for( f <- folderUsers ){
		    query = session.createQuery("from Clients where user_ID = " + f.asInstanceOf[Folder].getUserID )
		    var newClients = query.list().toArray
		    for( c <- newClients ){
		      clients = clients :+ c.asInstanceOf[Client]
		    }
		  }
	      for( c <- clients ){
	    	if( c.getClientID != changedFile.cid ){
	    	  ClientsUpdater.addUpdate(c.getClientID, 
	    	      new FileUpdate("changededFile", changedFile.name, changedFile.parent, changedFile.code))
	    	}
	      }
	      
	      session.flush
	      //checking if the old file still exists
	      query = session.createQuery("from File f where f.fileID = "+fileToChange.asInstanceOf[File].getFileID
	          							+" and f.size = "+fileToChange.asInstanceOf[File].getSize)
	      if(query.list.toArray.isEmpty){
	        //deleting actual file from disk
	        val fileToDelete = new java.io.File("storage\\" + fileToChange.asInstanceOf[File].getFileID)
	        fileToDelete.delete
	      }
	      session.flush
	      return true
	    }  
	    
    } catch { case (e : Exception)=>e.printStackTrace }
    session.flush
    return false
  }
/*
  def bla(changedFile: File2): Boolean = {
    val cfg = new Configuration()
    var sessionFactory = null.asInstanceOf[SessionFactory]
    var session = null.asInstanceOf[Session]
    try{
    sessionFactory = cfg.configure().buildSessionFactory()
    session = sessionFactory.openSession()
    //check if the new file exists on the DB
    var query = session.createQuery("from File f where f.fileID = " + changedFile.code +
    							" and f.size = " + changedFile.size)
    val fileInstances = query.list().toArray
    if (fileInstances.isEmpty) {
      return false
    }
    val fileManager = new FileManager(session)
    //deletes the old file from the database
    var oldFile = fileInstances.asInstanceOf[File]
    fileManager.deleteFile(oldFile)
    session.flush
    //check if to delete the actual file
    query = session.createQuery("from File f where f.fileID = "+oldFile.getFileID+" and f.size = "+oldFile.getSize)
    if(query.list.toArray.isEmpty){
      //deletes actual file from disk
      val file_ = new java.io.File("storage/" + oldFile.getFileID)
      file_.delete
    }
    session.flush
    
    /*
    //get the old file from the database
    query = session.createQuery("from File f where f.parentFolder = " + changedFile.parent +
      " and f.fileName = '" + changedFile.name + "'")
    val oldFile2 = query.list()
    if (oldFile2.isEmpty()) {
      return false
    }*/
    
    //adds the new file to the database
    val file = new File
    file.setFileID(changedFile.code)
    file.setFileName(changedFile.name)
    file.setSize(changedFile.size)
    file.setParentFolder(changedFile.parent)
    fileManager.saveFile(file)

    query = session.createQuery("from Folder f where f.folderID = " + changedFile.parent)
    //get the folder from the database in order to know who the users are
    val folderUsers = query.list().toArray

    val newFile = new File
    newFile.setFileID(changedFile.code)

    var clients = new LinkedList[Client]
    //collects all relevant clients
    for( f <- folderUsers ){
      query = session.createQuery("from Client c where c.userID = " + f.asInstanceOf[Folder].getUserID)
      var newClients = query.list().toArray
      for( c <- newClients ){
        clients = clients :+ c.asInstanceOf[Client]
      }
    }
    val client = new Client
    client.setUserID(changedFile.uid)
    client.setClientID(changedFile.cid)
    for( c <- clients ){
      if( c != client ){
        //!!!!!!!!!!!!!! need to add the bytes!!!!!!!!!!!!!!!!!
        ClientsUpdater.addUpdate(c.getClientID, new FileUpdate("changedFile", file.getFileName, 
        											file.getParentFolder, changedFile.code))
      }
    }
    
    /*
    folderUsers.foreach(f => {
      query = session.createQuery("from Clients where user_ID = '" + f.getUserID + "'")
      var newClients = query.list().asInstanceOf[List[Client]]
      clients.addAll(newClients)
    })
    //adds an update for each client
    clients.foreach(c => {
      if (c != client) {
        var update = new FileUpdate("ChangedFile", c, file) //!!!!!!!!!!!!!!
        ClientsUpdater.addUpdate(update, c)
      }
    })*/
    session.flush
    } catch { case (e : Exception) => println(e.printStackTrace) }
    return true
  }
*/
  
  
}

